#pragma once
#include"tcp_socket.hpp"
#include <signal.h>
#include <functional>

typedef std::function<void(const std::string& rep, std::string* resp)> Handler;

class TcpProcessServer
{
public:
    TcpProcessServer(const std::string& ip, uint16_t port):ip_(ip), port_(port)
    {
        signal(SIGCHLD, SIG_IGN);//IGN:ignore
        //当我的任何子进程结束时，不要给我发送SIGCHLD信号，我完全忽略它。
    }
    /// @brief 这是函数的简短描述，用于快速了解函数的主要功能。
    /// @param：这是参数的描述标签，后面跟着的是参数的名称和该参数的描述。
    /// @param new_sock 
    /// @param ip 
    /// @param port 
    /// @param handler 
    
    void ProcessConnect(TcpSocket& new_sock, const std::string& ip, uint16_t port, Handler handler)//处理连接
    {
        int ret = fork();//交给子进程处理，这样父进程从此层函数跳出，就可以继续Accept了，实现多进程！！！！！！！！
        if(ret > 0){
            //为什么父进程不需要额外的操作！！！！

            //父进程的主要职责是监听新的连接请求。
            //一旦有新的连接，父进程就通过调用ProcessConnect并创建一个子进程来处理这个连接。
            //父进程不应该被任何特定连接的细节所阻塞，以便它可以继续监听并处理其他新的连接。
            //如果父进程在fork()后使用wait()等待子进程结束，那么父进程将被阻塞，
            //直到子进程完成其任务。这会导致父进程不能再次调用accept()来接受新的连接，从而限制了服务器的并发处理能力
            new_sock.Close();
            return ;
        }else if(ret == 0)
        {
            // child
            // 处理具体的连接过程. 每个连接一个子进程
            for (;;) {
                std::string req;
                bool ret = new_sock.Recv(&req);
                if (!ret) {
                // 当前的请求处理完了, 可以退出子进程了. 注意, socket 的关闭在析构函数中就完成了
                    printf("[client %s:%d] disconnected!\n", ip.c_str(), port);
                    exit(0);
                }
                std::string resp;
                handler(req, &resp);
                new_sock.Send(resp);
                printf("[client %s:%d] req: %s, resp: %s\n", ip.c_str(), port, 
                req.c_str(), resp.c_str());
            }
        }else{
            perror("fork");
            //return;
        }
    }
    bool Start(Handler handler)
    {
        CHECK_RET(listen_sock.Socket());
        CHECK_RET(listen_sock.Bind(ip_, port_));
        CHECK_RET(listen_sock.Listen(5));//最大监听数
        for(;;)
        {
            TcpSocket new_sock;
            std::string ip;
            uint16_t port = 0;//监听所有端口
            if(!listen_sock.Accept(&new_sock, &ip, &port))//一直监听，只要不超过最大连接数，就可以接受连接请求
            {
                continue;
            }
            printf("[client %s:%d] connect~\n", ip.c_str(), port);
            ProcessConnect(new_sock, ip, port, handler);
        }
    }
private:
    TcpSocket listen_sock;
    std::string ip_;
    uint16_t port_;
};